(function () {

    console.log("NumberExtensions.js version: 2022-10-28 11:14:17");

    if (Number.setConfig) {
        return;
    }

    /**
     * 将变量转换为数字
     */
    Number.parse = function (str) {
        if (str == null) {
            return null;
        }
        if (typeof str === "number" && !isFinite(str)) {
            return str;
        }
        str = str.toString().trim().replace(/,(?=\d{3})/g, "");
        if (!/^[+-]?[0-9]+(\.([0-9])*)?(e[+-]\d+)?$/.test(str)) {
            return null;
        }
        var number = parseFloat(str);
        if (isNaN(number) || !isFinite(number)) {
            return null;
        }
        return number;
    }

    // 存到 localStorage 的前缀
    var prefix = "numberconfig:";
    var defaultConfig = { decimals: 4, mode: "Round", thousands: true, zreofill: false, align: "left", units: {} };

    /**
     * 清空配置 
     */
    Number.clearConfig = function () {
        for (var key of Object.keys(localStorage)) {
            if (key.toLocaleLowerCase().startsWith(prefix)) {
                localStorage.removeItem(key)
            }
        }
    }

    /**
     * 获取指定样式的小数配置
     * @param {String} style 样式名称
     * @param {String} unit 单位
     */
    Number.getConfig = function (style, unit) {
        if (style == null) {
            return defaultConfig;
        }
        var key = (prefix + style).toLowerCase();
        var json = localStorage.getItem(key);
        if (json == null) {
            return defaultConfig;
        }
        if (json.charAt(0) !== "{") {
            json = localStorage.getItem(json)
        }
        var config = JSON.parse(json);

        if (unit != null && config.units != null) {
            return config.units[unit] || config;
        }
        return config;
    }


    /**
     * 设置小数样式
     * @param {String|String[]} styleKeys 样式名称和别名。如：["price","p"]
     * @param {Object} config 配置。如： { decimals: 4, mode: "Round", thousands: true, zreofill: false, align: "left", units: {} };
     * @param {String} unit 单位
     */
    Number.setConfig = function (styleKeys, config, unit) {
        if (styleKeys == null) {
            return;
        }

        if (typeof styleKeys === "string") {
            styleKeys = [styleKeys];
        }

        // config is null 表示删除
        if (config == null) {
            // 没有单位表示删除所有
            if (unit == null) {
                for (var i = 0; i < styleKeys.length; i++) {
                    localStorage.removeItem(pre + styleKeys[i].toLowerCase());
                }
            } else {
                config = Number.getConfig(styleKeys[0]);
                if (config != null) {
                    // 仅删除指定单位的配置
                    delete config.units[unit];
                }
            }
            return;
        }

        if (config.decimals != null && Number.parse(config.decimals) == null) {
            throw new Error("decimals 必须是数字");
            config.decimals = Number.parse(config.decimals);
            if (config.decimals < 0 || config.decimals > 20) {
                throw new Error("decimals 不能小于0或大于20");
            }
        }

        // 获取当前配置
        var currentConfig = Number.getConfig(styleKeys[0]);
        if (currentConfig == null) {
            currentConfig = defaultConfig;
        }
        currentConfig = Object.assign({}, currentConfig);
        // 将新配置追加到当前
        for (var key of Object.keys(config)) {
            var val = config[key];
            if (val != null) {
                currentConfig[key] = val;
            }
        }

        var json = JSON.stringify(currentConfig)
        var style = (prefix + styleKeys[0]).toLowerCase();
        // 保存配置
        localStorage.setItem(style, json);
        // 关联保存
        for (var alias of styleKeys.slice(1)) {
            localStorage.setItem((prefix + alias).toLowerCase(), style);
        }
    }


    /**
     * 移动小数点
     * @param {Number} number 数字
     * @param {Number} move 小数点移动位数
     */
    function movePoint(number, move) {

        move = parseInt(move);
        if (isNaN(move) || move < -20 || move > 20) {
            throw Error("move不能大于20或小于-20")
        }

        var str = overflowString(number);
        var point = str.indexOf(".");
        var arr = str.split("");
        if (move != 0) {
            arr.splice(point, 1);
            arr.splice(point + move, 0, ".");
        }
        return arr.join("");
    }

    /**
     * 字符串前后补0，方便后续操作
     * @param {Number} number 需要补0的数字
     * @param {Number} zeroLength 前后补0的个数
     */
    function overflowString(number, zeroLength) {
        zeroLength = Number.parse(zeroLength) || 20;
        if (zeroLength < 0) {
            zeroLength = 20;
        }
        var symbol = number < 0 ? '-' : "";
        number = Math.abs(number);
        // 将20位以内的科学计数法数字转为纯数字
        var str = number.toLocaleString("zh-CN", { maximumFractionDigits: 20 }).replace(/[,]/g, "");
        var zero = new Array(zeroLength).fill("0").join("");
        var point = str.indexOf(".") < 0 ? "." : ""; // 添加小数点
        return symbol + zero + str + point + zero;
    }


    /**
     * 剪切小数
     * @param {Number|String} number 数字或表示数字的字符串
     * @param {String} style 样式名称
     * @param {String} unit 单位
     */
    Number.scale = function (number, style, unit) {
        number = Number.parse(number);
        if (number == null) {
            return null;
        }
        var config = Number.getConfig(style, unit);

        var func = Math[config.mode.toLowerCase()] || Math.ceil;
        // 将数字放大  
        var number = movePoint(number, config.decimals);
        // 剪切小数
        number = func(number);
        // 数字缩小
        return Number.parse(movePoint(number, -config.decimals));

    }

    /**
     * 格式化数字
     * @param {any} number 数字
     * @param {any} style 样式
     * @param {any} unit 单位
     */
    Number.format = function (number, style, unit) {
        number = Number.parse(number);
        if (number == null) {
            return null;
        }
        var config = Number.getConfig(style, unit);

        var str = number.toLocaleString("zh-CN", { maximumFractionDigits: 20 });

        // 处理千分位
        if (!config.thousands) {
            str = str.replace(/,/g, "");
        }

        // 处理补零
        if (config.decimals > 0 && config.zreofill) {
            if (str.indexOf(".") < 0) {
                str += ".";
            }
            str = (str + "00000000000000000000").replace(new RegExp("(?<=\\.\\d{" + config.decimals + ",})0+$"), "")
        }
        return str;
    }


    /**
     * 剪切小数 + 格式化
     * @param {any} number 数字
     * @param {any} style 样式
     * @param {any} unit 单位
     */
    Number.scaleformat = function (number, style, unit) {
        return Number.format(Number.scale(number, style, unit), style, unit);
    }


    Number.prototype.format = function (style, unit) {
        return Number.format(this, style, unit);
    }

    /**
     * 剪切小数
     * @param {String} style 样式名称
     * @param {String} unit 单位
     */
    Number.prototype.scale = function (style, unit) {
        return Number.scale(this, style, unit);
    }

    /**
     * 剪切小数 + 格式化
     * @param {String} style 样式名称
     * @param {String} unit 单位
     */
    Number.prototype.scaleformat = function (style, unit) {
        return Number.scaleformat(this, style, unit);
    }

})();